package com.dji.pa.cluster.db.dataSouce;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;

public class ServerWatcher implements Runnable{
    private final Logger log=LoggerFactory.getLogger(ServerWatcher.class);
	private List<Server> failServerList=null;
	private final AbstractClusterDataSource cds;
	private final Lock lock;

	public ServerWatcher(AbstractClusterDataSource cds,Lock lock){
		this.lock=lock;
		this.failServerList=new LinkedList<Server>();
		this.cds=cds;
	}

	public List<Server> getFailServerList(){
		return failServerList;
	}

	public void run(){
		while(true){
			if(CollectionUtils.isEmpty(failServerList)){
				log.debug("监控：暂无异常服务器....");
				synchronized(lock){
					try{
						lock.wait();
					}catch(InterruptedException e){

					}
				}
			}else{
				Iterator<Server> iterator=failServerList.iterator();
				Server failServer=null;
				while(iterator.hasNext()){
					failServer=iterator.next();
					try{
						log.debug("监控：连接失败服务器总计 "+failServerList.size()+"台，当前正在测试:"+failServer.getIpAndPort());
						if(failServer.getDataSource().getConnection().isValid(2000)){// 故障服务器恢复再加锁处理,否则影响正常服务器切换

							if(lock.tryLock(1,TimeUnit.SECONDS) && failServerList.contains(failServer)){//多个线程同时进行到这一步第一个已经删除了第二个获得锁就出问题
								try{
									log.debug("监控：获取锁"+failServer.getIpAndPort()+"恢复正常");
									if(failServer.getServerType()==Server.READ){// 读服务器恢复的时候如果原先用了写服务器，就要将写服务器从目前的读服务器列表删除
										for(int item=0;item<cds.getReadDBList().size();item++){
											if(cds.getReadDBList().get(item).getServerType()==Server.WRITE){
												cds.getReadDBList().remove(item);
											}
										}
										cds.getReadDBList().add(failServer);
										log.debug("将"+failServer.getIpAndPort()+"恢复到读序列");
									}else if(failServer.getServerType()==Server.WRITE){
										log.debug("将"+failServer.getIpAndPort()+"恢复到写序列");
										cds.getWriteDBList().add(failServer);
										for(int item=0;item<cds.getWriteDBList().size();item++){
											if(cds.getWriteDBList().get(item).getServerType()!=Server.WRITE){
												cds.getReadDBList().add(cds.getWriteDBList().remove(item));
											}
										}
									}else if(failServer.getServerType()==Server.READWRITE){
										cds.getReadDBList().add(failServer);
										cds.getWriteDBList().add(failServer);
										log.debug("将"+failServer.getIpAndPort()+"恢复到可读可写序列");
									}
									iterator.remove();
									log.debug("监视器:"+failServer.getIpAndPort()+"恢复正常,从失败服务器列表删除");
								}catch(Exception e){
									log.error("监视器:异常",e);
								}finally{
									lock.unlock();
									log.debug("监视器:3333333333333333  释放锁");
								}
							}else{
								log.debug("监视器:"+failServer.getIpAndPort()+"恢复正常,暂时无法获取锁");
							}
						}
					}catch(Exception e){
						log.debug("监视器：连接尚未恢复");
						// 这里测试连接性超时抛异常，不用管
					}
				}
			}
		}
	}
}
